package com.gopay.scheduler;


import com.gopay.common.constants.scheduler.SchedulerConstants;
import com.gopay.common.util.DateUtils;
import com.gopay.scheduler.shedulerx.SchedulerOperateFactory;
import com.gopay.scheduler.shedulerx.alarm.AlarmEvent;
import com.gopay.scheduler.shedulerx.event.ProcessorJobEvent;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.UUID;

/**
 * @author 19371
 */
public class JobProcessorWrapper {

    private final static JobProcessorWrapper jobProcessorWrapper = new JobProcessorWrapper();

    private JobProcessorWrapper() {
    }

    public static JobProcessorWrapper getSingle(){
        return jobProcessorWrapper;
    }

    private static final String yyyy_MM_dd_HH_mm_ss_SSS = "yyyy-MM-dd' 'HH:mm:ss SSS";

    public void doJobInternal(GopayBaseJob gopayBaseJob) throws Exception {
        if(SchedulerOperateFactory.getFactory().isSchedulerX()) {
            tracer(gopayBaseJob);
        }else {
            gopayBaseJob.doJobInternal();
        }
    }

    private final void tracer(GopayBaseJob gopayBaseJob) throws Exception {
        if(gopayBaseJob != null) {
            String className = gopayBaseJob.getClass().getName();
            SchedulerOperateFactory operateFactory = SchedulerOperateFactory.getFactory();
            boolean trace = operateFactory.isTrace(className);
            ProcessorJobEvent event = null;
            String state = SchedulerConstants.JOB_PROCESSOR_END;
            String msg = "";
            String uuid = "";
            String finishTime = "";
            if(trace) {
                uuid = UUID.randomUUID().toString().replace("-", "");
            }
            /**
             * redis不做waiting判断，请设置concurrent = false，来避免并发问题
             */
            operateFactory.markRunning(className, uuid);
            Exception ex = null;
                if (trace) {
                    event = new ProcessorJobEvent();
                    event.setJobUid(uuid);
                    event.setSchedulerState(SchedulerConstants.JOB_PROCESSOR_START);
                    event.setStartTime(DateUtils.format(new Date(), yyyy_MM_dd_HH_mm_ss_SSS));
                    operateFactory.postTraceEvent(event, className);
                }
                try {
                    gopayBaseJob.doJobInternal();
                    finishTime = DateUtils.format(new Date(), yyyy_MM_dd_HH_mm_ss_SSS);
                } catch (Exception e) {
                    finishTime = DateUtils.format(new Date(), yyyy_MM_dd_HH_mm_ss_SSS);
                    state = SchedulerConstants.JOB_PROCESSOR_EXCEPTION;
                    msg = e.getCause() == null ? e.getMessage() : String.format("%s:%s",e.getCause().getClass(),e.getCause().getMessage());
                    String level = operateFactory.getAlarmLevelMapping().get(className);
                    if (!SchedulerConstants.SCHEDULER_ALARM_NOMAL.equals(level)) {
                        AlarmEvent alarmEvent = new AlarmEvent();
                        alarmEvent.setAlarmLevel(level);
                        alarmEvent.setEventTime(DateUtils.format(new Date(), yyyy_MM_dd_HH_mm_ss_SSS));
                        operateFactory.alarm(alarmEvent, className);
                    }
                    ex = e;
                } finally {
                    if (trace && event != null) {
                        event.setSchedulerState(state);
                        if (StringUtils.isNotBlank(msg)) {
                            if (msg.length() < 250) {
                                event.setErrorMsg(msg);
                            } else {
                                event.setErrorMsg(msg.substring(0, 249));
                            }
                        }
                        event.setEndTime(StringUtils.isBlank(finishTime) ? DateUtils.format(new Date(), yyyy_MM_dd_HH_mm_ss_SSS) : finishTime);
                        /**
                         * 宕机或关机时候或异常，可能有状态不一致的情况
                         */
                        operateFactory.postTraceEvent(event, className);
                    }
                    operateFactory.markWaiting(className);
                    if (ex != null) {
                        throw ex;
                    }else {
                        operateFactory.resetAlarmCount(className);
                    }
                }
        }
    }
}
